home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Alles Voor Internet / Tout Pour Internet
/
alles voor internet.iso
/
MacInternet™
/
Unix
/
maclayersunixend1.30.shar
/
1.30
/
protocol.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-17
|
37KB
|
1,357 lines
/* Copyright (C) 1989 by David W. Trissel
*
* Not derived from licensed software.
*
* Permission is granted to freely use, copy, modify, and redistribute
* this software, provided that no attempt is made to gain profit from it,
* the author is not construed to be liable for any results of using the
* software, alterations are clearly marked as such, and this notice is
* not modified.
*
*/
#include <stdio.h>
#ifdef NeXT
#include <libc.h>
#endif
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include "layers.h"
/* protocol.c - BSD MacLayers protocol driver */
/* This module handles all interaction with the Macintosh MacLayers
** program. Services provided are:
**
** InitLink() - initialize link to MacLayers
**
** TopChannel() - return highest prority channel
**
** SendNew() - request new layer channel of MacLayers
**
** SendTitle() - change window title to given string (NOT IMPLENTED YET)
**
** SendDelete()- tell MacLayers indicated layer has died
**
** SendQuit() - order MacLayers to terminate layers mode
**
** SendData() - send output to indicated channel's window
**
** SendReshape() - send Shape structure to MacLayers
**
** ProcessStreamin() - data is ready to be processed from MacLayers
**
*/
#define DUMPALL
#undef DUMPALL
/* C library calls */
#ifndef NeXT
unsigned alarm(); /* alarm system call */
#endif
static int Start_proto1();
static int Start_proto2();
static int Start_proto3();
static int Start_proto4();
static int Start_proto5();
static int Start_proto6();
static int Start_proto7();
static int Start_proto8();
static int GetData();
static void Packet();
static void Parse();
static void AwaitInput();
static void asciishape();
static void fill4();
static void fill2();
static void fill1();
static int parseshape();
static unsigned get4();
static unsigned get2();
static unsigned get1();
static int myscanf();
static int mygetchar();
static void myungetc();
static void myalarm();
static void dumptime();
static char inbuff[IOSIZE]; /* input buffer from MacLayers */
static char *inpos; /* current input position in buffer */
static int insize = 0; /* characters left to process */
static int settimeout = 0; /* alarm system call timeout value */
static int Outstream = -1; /* current output stream channel */
static int Instream = -1; /* current input stream channel */
static int Sevenbits = 0; /* communication channel is 7 bits */
static struct Shape SNshape; /* SendNew() shape response */
static int SNresp = 0; /* SendNew() reponse poll flag */
static int SNchan = 0; /* SendNew() channel return */
#define SN_WAITING -1000 /* SendNew() waiting response value */
#define ATTRSIZE 15 /* size of window attribute string */
#define FLUSH fflush(stdout)
/* Initlink() - initialize link with MacLayers */
/* Returns:
** 0 - linkup failed
** 1 - linkup successful, Maclayers now in protocol mode
*/
int
Initlink()
{
int Outstream = -1; /* no default stream yet [UNUSED] */
int Instream = -1; /* no default stream yet [UNUSED] */
int num1, num2, num3; /* scanf item result */
int err; /* error code */
int doversion = 0; /* version swapping flag [UNUSED] */
#define WAITTIME 10 /* second wait response time */
#define INITTIME 2 /* wait time after succesful startup */
/*** This patch not yet tested or implemented. Sent to the MacLayers archive
**** as:
This patch fixes the "Encode request not from host" bug that occurs when
running MacLayers 1.00 on a VaxStation 3100 and Ultrix 3.1d.
I came across this patch rather accidentally, so take it with a grain of
NaCl.
ifndef vax
/* we must non-buffer input since all input must be immediate
setbuf(stdin, NULL); /* non-buffer all input
endif
Archive manager Peter Newton added the following comments:
Don't have a VaxStation to try it one. Many people have had problems
with Ultrix on VaxStations. We have been giving them uuencoded
binaries made under BSD.
*****************/
/* V1.1 Note: The latest BSD Sun system doesn't break reads from the
** terminal during signals. It appears that System V does do this
** as do earlier BSD systems. At this time no special hacks will
** be installed in just to support Unix versions not doing the breaks.
** Without alarm timeouts host layers will hang if inappropriate
** responses are received during protocol startup. But this should
** only happen when a user types the layers command when not running
** MacLayers.
*/
/* we must non-buffer input since all input must be immediate */
setbuf(stdin, NULL); /* non-buffer all input */
/* Host layers after V1.00 can receive protocol level information.
** Send our level as ESC <id>. Version 1.00 MacLayers will treat
** this as an illegal vt-100 sequence and issue a beep. Later versions
** accept our protocol level and return their own after receiving
** our protocol startup sequence sent here.
*/
DO DEBUG("write protocol level 2: ESC 2\n");
/* send our protocol level out */
if ((err=printf("\033%c", HOSTPROTOCOL + '0')) < 0)
{ DO DEBUG(" printf() error code %d\n", err);
return ( 0 ); /* problem with stdout */
}
FLUSH;
/* send intitial request for terminal type and version number */
DO DEBUG("write: ESC [ c\n");
fputs("\033[c", stdout);
FLUSH; /* force output buffer */
/* Attempt to read "ESC [ ? 8 ; typedigits ; versiondigits c"
** MacLayers in layers mode will return 8 ; 1 c
** MacLayers in startup mode returns 8 ; X c
** were X is the protocol level
*/
num1 = num2 = num3 = -1; /* default to unsupplied values */
DO DEBUG(" doing first scanf\n");
(void) myalarm(WAITTIME); /* set timeout */
(void) myscanf("\033[?%d;%d;%dc", &num1, &num2, &num3);
(void) myalarm(0); /* cancel alarm */
DO DEBUG("read ESC [ ? %d ; %d; %d c\n", num1, num2, num3);
if (num1 != 8 || num2 != 10)
return ( 0 ); /* not correct response or layers term ID */
DO DEBUG("Client Protocol %d, Host Protocol %d\n", num3, HOSTPROTOCOL);
/* Terminal type was valid, now verify protocol number */
switch (num3)
{ case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
/* these are all valid levels */
break; /* break for valid levels */
case 9:
num3 = 7; /* 9 represents level 7 */
break;
case 0:
num3 = 8; /* 0 represents level 8 */
break;
default:
/* invalid response */
return ( 0 ); /* incorrect protocol level */
} /* client protocol level switch */
Clientlevel = num3; /* set client protocol level offered */
/* final protocol level cannot be higher than our current support level */
if (num3 > HOSTPROTOCOL)
{ DO DEBUG("Protocol level forced down to host level\n");
num3 = HOSTPROTOCOL; /* force back down to the host level */
}
Protocollevel = num3; /* set effective protocol level */
/* execute proper startup protocol level routine */
switch (Protocollevel)
{ case 1:
return ( Start_proto1() ); /* handle protocol 1 startup sequence */
case 2:
return ( Start_proto2() ); /* handle protocol 2 startup sequence */
case 3:
return ( Start_proto3() ); /* handle protocol 3 startup sequence */
case 4:
return ( Start_proto4() ); /* handle protocol 4 startup sequence */
case 5:
return ( Start_proto5() ); /* handle protocol 5 startup sequence */
case 6:
return ( Start_proto6() ); /* handle protocol 6 startup sequence */
case 7:
return ( Start_proto7() ); /* handle protocol 7 startup sequence */
case 8:
return ( Start_proto8() ); /* handle protocol 8 startup sequence */
}
/* invalid - refuse startup */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Initlink() */
/* Start_proto1() - Protocol 1 startup sequence */
static int
Start_proto1()
{
int num1; /* scanf item result */
/* This is the original MacLayers protocol for V1.00 */
/* ask terminal if ENC_ENABLE is to be forced */
DO DEBUG("write: ESC [ F\n");
(void) fputs("\033[F", stdout);
FLUSH; /* force output buffer */
/* attempt to read "ESC [ flag F" (flag indicates ENC_ENABLE status) */
num1 = -1; /* default to invalid response */
myalarm(WAITTIME); /* set timeout */
(void) myscanf("\033[%dF", &num1);
myalarm(0); /* cancel alarm */
DO DEBUG("read ESC [ %d F\n", num1);
if (num1 != 1 && num1 != 0)
return ( 0 ); /* something's wrong */
if (num1 == 1)
Sevenbits = 1; /* we are processing 7-bit data */
/* now startup packet mode in non ENC_ENABLE processing */
DO DEBUG("write: ESC [ 2 ; 0 v\n");
(void) fputs("\033[2;0v", stdout); /* "ESC [ 2 ; 0 v" */
FLUSH; /* force output buffer */
#if 0
{ int i,j;
for (i=0; i<20; i++)
{ j = mygetchar();
DO DEBUG("---- read 0x%lx == %c\n", j, j);
}
return (0 );
}
#endif
#if 0
/* We must reset buffer to reread this character. Note
** this won't work for triggering reads by layers.c unless
** client is sending more than 1 character because the select()
** system call is used.
*/
/* ungetc(num1, stdin); /* return character back for re-read */
myungetc(num1); /* re-insert this character */
#endif
#if 0
insize = 1; /* preset buffer with one character */
inpos = inbuff; /* setup buffer pointer */
inbuff[0] = num1; /* setup to reread this character */
#endif
Clientlevel = 1; /* assume protocol is level 1 */
/* we are now in packet mode */
sleep( INITTIME ); /* let Macintosh keep up with us */
return ( 1 ); /* return successful startup */
} /* Start_proto1() */
/* Start_proto2() - Protocol 2 startup sequence */
static int
Start_proto2()
{
/* This is the second MacLayers protocol starting with V1.1 */
/* we are now in packet mode */
sleep( INITTIME ); /* let Macintosh keep up with us */
return ( 1 ); /* return successful startup */
} /* Start_proto2() */
/* Start_proto3() - Protocol 3 startup sequence */
static int
Start_proto3()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto3() */
/* Start_proto4() - Protocol 4 startup sequence */
static int
Start_proto4()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto4() */
/* Start_proto5() - Protocol 5 startup sequence */
static int
Start_proto5()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto5() */
/* Start_proto6() - Protocol 6 startup sequence */
static int
Start_proto6()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto6() */
/* Start_proto7() - Protocol 7 startup sequence */
static int
Start_proto7()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto7() */
/* Start_proto8() - Protocol 8 startup sequence */
static int
Start_proto8()
{
/* not yet defined! */
return ( 0 ); /* SHOULD NOT OCCUR */
} /* Start_proto8() */
/* TopChannel() - return highest prority channel */
int
TopChannel()
{
return ( Instream );
} /* TopChannel() */
/*
** WARNING: Most of the following functions may be recursively called
** as control commands are processed from the input stream
*/
/* ProcessStreamin() - MacLayers has input to process */
void
ProcessStreamin()
{
DO dumptime();
DO DEBUG("ProcessStreamin() insize %d\n", insize);
GetData(); /* read some */
while (insize > 0) /* while more data to process ... */
Parse(); /* process next chuck of data */
} /* ProcessStreamin() */
/* SendNew() - request new layer channel from MacLayers */
/* This command is unique in that it returns a response from MacLayers.
** To do this we continue processing the input stream until we get
** our return. (This leads to recursive conditions.) The variables
** 'SNresp', 'SNshape' and 'SNchan' are set when our reply is received.
*/
int
SendNew(shape)
struct Shape *shape; /* shape to use for new window */
{
int i; /* attribute count variable */
char astring[ATTRSIZE]; /* copy of attribute string */
DO dumptime();
DO DEBUG("SendNew() new layer requested: '~%cA'\n", '1'+ATTRSIZE);
/* check for a recursive call */
if (SNresp == SN_WAITING)
{ DO DEBUG("return 0 - recursive call\n");
return ( 0 ); /* return failure */
}
putchar(ESCAPE); /* send start of control packet char */
putchar('1' + ATTRSIZE); /* send command size */
putchar('A'); /* send command */
asciishape(shape, astring); /* convert shape to string */
for (i=0; i < ATTRSIZE; i++)
putchar(astring[i]); /* send next attribute digit */
FLUSH;
/* now stay here and process the input stream until we see our response */
/**** THIS SHOULD BE ENHANCED TO TIMEOUT WITH GetData() AND REISSUE REQUEST */
SNresp = SN_WAITING; /* indicate we are waiting a response */
while (SNresp == SN_WAITING)
{ DO DEBUG(" while (SNresp %d == %d)\n", SNresp, SN_WAITING);
AwaitInput(); /* wait till input from MacLayers arrives */
ProcessStreamin(); /* process available input */
}
if (SNresp == -1) /* if Maclayers rejected request */
SNchan = 0; /* return failure channel of zero */
else
*shape = SNshape; /* else update shape structure */
DO DEBUG("SendNew() returning channel %d\n", SNchan);
return ( SNchan ); /* return the indicated channel */
} /* SendNew() */
/* SendReshape() - send to shape to MacLayers */
void
SendReshape(chan, shape)
int chan; /* channel shape belongs to */
struct Shape *shape; /* shape to use for new window */
{
int i; /* attribute count variable */
char astring[ATTRSIZE]; /* copy of attribute string */
DO dumptime();
DO DEBUG("SendReshape() reshape: '~%cA'\n", '2'+ATTRSIZE);
if (chan <= 0 || chan > MAXPCHAN)
{ DO DEBUG("BAD CHANNEL!!!\n");
return; /* ignore request */
}
putchar(ESCAPE); /* send start of control packet char */
putchar('2' + ATTRSIZE); /* send command size */
putchar('R'); /* send command */
putchar(chan + '0'); /* send channel */
asciishape(shape, astring); /* convert shape to string */
DO DEBUG("shape: %.*s\n", ATTRSIZE, astring);
for (i=0; i < ATTRSIZE; i++)
putchar(astring[i]); /* send next attribute digit */
FLUSH;
} /* SendReshape() */
/* SendTitle() - set layer's window title */
void
SendTitle(chan, buff, cnt)
int chan; /* layer window ID */
char *buff; /* new title string */
int cnt; /* count of title length */
{
int i; /* work variable */
DO DEBUG("SendTitle(chan%d, len %d, '%.*s')\n", chan, cnt, cnt, buff);
if (chan <= 0 || chan > MAXPCHAN)
{ DO DEBUG("BAD CHANNEL!!!\n");
return; /* ignore request */
}
if (cnt < 0)
{ DO DEBUG("BAD COUNT!!!\n");
return; /* ignore request */
}
/* for now chop title size to 29 chars since that's MacLayer's limit */
if (cnt > 29)
cnt = 29; /* due to packet size limit */
/* we must guarantee that the size will not appear to be another ESCAPE */
if ('2' + cnt == ESCAPE)
cnt--; /* truncate to avoid ESCAPE ESCAPE */
putchar(ESCAPE); /* send start of control packet char */
putchar('2' + cnt); /* send size of packet */
putchar('T'); /* send command */
putchar(chan + '0'); /* send channel ID */
for (i=0; i<cnt; i++)
putchar(buff[i]); /* send out title */
FLUSH;
} /* SendTitle() */
/* SendDelete() - tell Maclayers layer died */
void
SendDelete(chan)
int chan; /* dead channel ID */
{
DO DEBUG("SendDelete(%d) '~2D%d'\n", chan, chan);
if (chan <= 0 || chan > MAXPCHAN) /* check channel ID */
{ DO DEBUG("BAD CHANNEL!!!\n");
return; /* ignore request */
}
putchar(ESCAPE); /* send control packet start char */
putchar('2'); /* send command size */
putchar('D'); /* send command character */
putchar(chan + '0'); /* channel ID in ascii */
FLUSH;
} /* SendDelete() */
/* SendQuit() - order MacLayers to end layers mode */
void
SendQuit(chan)
int chan; /* dead channel ID */
{
DO dumptime();
DO DEBUG("SendQuit() '~1E'\n");
putchar(ESCAPE); /* send control packet start char */
putchar('1'); /* send command size */
putchar('E'); /* send command */
FLUSH;
} /* SendQuit() */
/* SendData() - send output to layer's window */
void
SendData(chan, buff, cnt)
int chan; /* layer window ID */
unsigned char *buff; /* new title string */
int cnt; /* count of title length */
{
unsigned c; /* output character being sent */
DO
{ int dcnt;
dumptime();
DEBUG("SendData(chan %d, len %d, '", chan, cnt, cnt, buff);
for (dcnt=0; dcnt<cnt; dcnt++)
DEBUG("%c", buff[dcnt]); /* dump each char so null doesn't stop */
DEBUG("')\n");
}
if (chan <= 0 || chan > MAXPCHAN)
{ DO DEBUG("BAD CHANNEL!!!\n");
return; /* ignore request */
}
/* if new output channel stream then prefix redirect command */
if (chan != Outstream)
{ DO DEBUG("Redirecting output to %d '~2O%d'\n", chan, chan);
putchar(ESCAPE); /* start of command sequence */
putchar('2'); /* send command size */
putchar('O'); /* send command */
putchar(chan + '0'); /* put out channel in ASCII */
Outstream = chan; /* new output stream set */
}
/* transmit the buffer converting the ESCAPE sequence to double ESCAPE */
while (cnt--)
{ c = *buff++; /* get next output character */
#ifdef DUMPALL
DO DEBUG("outchar %c 0x%x\n", c, c);
#endif
if (c == ESCAPE || c == (ESCAPE + 0x80))
{ putchar(c); /* put it out twice */
#ifdef DUMPALL
DO DEBUG(" Doubled Escape!\n");
#endif
}
putchar(c); /* write character out */
}
FLUSH; /* force out queued output characters */
} /* SendData() */
/* Parse() - process next chunk of input stream */
static void
Parse()
{
#define ST_NULL 0 /* not primed for next state yet */
#define ST_STREAM 1 /* processing default stream input */
#define ST_PKT 2 /* processing packet data */
int c; /* input character being processed */
static int state = ST_NULL; /* current input state */
static int psize = 0; /* packet size */
static int rempsize = 0; /* remembered packet size */
static char pdata[MAXSTR]; /* area for packet data */
static char *ppos; /* packet read insert position */
static int escapemode = 0; /* processing escape character */
static int escapechar; /* escape character being processed */
static pchan = -1; /* packet input stream channel */
DO dumptime();
DO DEBUG("Parse() insize %d\n", insize);
while (insize-- > 0) /* while more data */
{ c = (*inpos++ & 0xFF); /* get next character (don't sign extend) */
switch (state) /* process according to state */
{ case ST_NULL: /* prepare for new packet */
DO DEBUG("ST_NULL\n");
psize = 0; /* clear packet size */
ppos = pdata; /* start fill at data position */
pchan = Instream; /* packet channel is current input stream */
state = ST_STREAM; /* default is stream processing */
case ST_STREAM:
/* stream keyboard input for layer */
/* check for escape char with possible high bit on */
#ifdef DUMPALL
DO DEBUG("ST_STREAM %x/%x '%c' esc %d insz %d\n",
c, c & 0x7f, c & 0x7f, escapemode, insize);
#endif
if (c == ESCAPE || c == (ESCAPE | 0x80))
{ if (escapemode && c == escapechar) /* previous was ESCAPE */
/* this is really a single ESCAPE character */
escapemode = 0; /* back out of ESCAPE mode */
else
/* what do we do with back to back esc esc+0x80 ? */
{ /* flag in escape mode */
escapemode++;
escapechar = c; /* remember character used for escape */
continue; /* and continue scan */
}
}
else
if (escapemode)
{ /* this is the start of a control packet */
if (psize) /* if we have previous data packet */
Packet(pchan, psize, pdata); /* finish up previous pkt */
/* process packet size */
psize = (c & 0x7f) - '0'; /* save size byte */
if (psize <= 0 || psize > MAXSTR)
{ /* bad size */
DO DEBUG("Bad pkt size %d\n", psize);
break; /* trash this packet */
}
rempsize = psize; /* remember this size for later */
#if 0
ptimo = rtimo; /* start receive timeout */
#endif
escapemode = 0; /* escape mode now off */
ppos = pdata; /* initialize data store pointer */
state = ST_PKT; /* expect packet data next */
continue; /* continue scan */
}
/* process standard data output character for current stream */
*ppos++ = c; /* save next data character */
if (++psize >= MAXSTR) /* if packet full ... */
{ Packet(pchan, psize, pdata); /* process this packet */
break; /* end packet processing */
}
continue; /* continue scan */
case ST_PKT:
/* process next paket data byte */
*ppos++ = c & 0x7f; /* store next data byte */
#ifdef DUMPALL
DO DEBUG("ST_PKT: %x '%c' sz %d\n", c & 0x7f, c & 0x7f, psize);
#endif
if (--psize != 0)
continue;
#if 0
if (crc((unsigned char *) &rpkt, rpkt.pkt.HEADER_DSIZE+2))
STATS(Scrcerr); /* communications error */
else
#endif
Packet(0, rempsize, pdata); /* process it */
} /* end build packet switch */
#if 0
ptimo = 0; /* no more receive timeout */
#endif
state = ST_NULL; /* no more receive packet in progress */
} /* end while (insize) */
if (state == ST_STREAM && psize ) /* if we have some data ... */
{ Packet(Instream, psize, pdata); /* process this data */
#if 0
ptimo = 0; /* no more receive timeout */
#endif
state = ST_NULL; /* no more receive packet in progress */
}
} /* Parse() */
/* Packet() - prcess next input data string or control packet */
static void
Packet(chan, size, buff)
int chan; /* channel (0 if control packet) */
int size; /* amount of data */
char *buff; /* pointer to packet data */
{
static struct Shape shape; /* Shape structure */
DO dumptime();
DO DEBUG("Packet(chan %d, size %d, '%.*s')\n", chan, size, size, buff);
/* verify channel */
if (chan < 0 || chan > MAXPCHAN)
{ DO DEBUG("BAD CHANNEL!!\n");
return; /* ignore bad channel */
}
/* if data packet (chan>0) feed data to server */
if (chan > 0)
{ ReceiveData(chan, buff, size);
return; /* we are through */
}
/* control packet (channel 0) */
chan = buff[1] - '0'; /* assume channel specified */
if (chan < 0 || chan > MAXPCHAN) /* if invalid ... */
chan = 0; /* set to zero */
switch (buff[0])
{ case 'I': /* redirect stream */
DO DEBUG("CMD 'I' redirect stream to %c\n", buff[1]);
if (size != 2) /* verify size */
break; /* break if bad */
if (chan == 0) /* verify channel */
break; /* break if bad */
Instream = chan; /* new instream channel */
return; /* we are through */
case 'A': /* returned A_NEWLAYER packet */
DO DEBUG("CMD 'A' A_NEWLAYER response %c newchan %c SNresp %d\n",
buff[2], buff[1], SNresp);
if (size != 3 + ATTRSIZE)
break; /* break if bad */
/* if SendNew() not waiting for a response this is invalid */
if (SNresp != SN_WAITING)
break; /* break if bad */
if (buff[2] == '1') /* if response is "failed" ... */
SNresp = -1; /* show -1 response */
else
if (buff[2] == '0') /* if response is "success" ... */
{ if (chan == 0) /* if invalid channel */
break; /* break if bad */
/* build shape structure for SendNew() */
if (parseshape(&SNshape, &buff[3]) == -1)
break; /* if invalid data then bad packet */
SNresp = 0; /* show good response */
SNchan = chan; /* indicate channel returned */
}
else
break; /* break if bad */
DO DEBUG("SNresp = %d, SNchan = %d\n", SNresp, SNchan);
return; /* we are through */
case 'N': /* new layer creation */
DO DEBUG("CMD 'N' new layer creation newchan %c\n", buff[1]);
if (size != 2 + ATTRSIZE) /* verify size */
break; /* break if bad */
if (chan == 0) /* verify channel */
break; /* break if bad */
/* build shape structure */
if (parseshape(&shape, &buff[2]) == -1)
break; /* if invalid data then bad packet */
ReceiveNew(chan, &shape); /* pass to server */
return; /* packet is done */
case 'D': /* deleted layer */
DO DEBUG("CMD 'D' deleted layer %c\n", buff[1]);
if (size != 2) /* verify size */
break; /* break if bad */
if (chan == 0) /* verify channel */
break; /* break if bad */
ReceiveDelete(chan); /* pass on to server */
return; /* packet is done */
case 'E': /* exit - awaiting shutdown */
DO DEBUG("CMD 'E' exit MacLayers awaiting shutdown msg\n");
if (size != 1) /* verify size */
break; /* break if bad */
ReceiveQuit(); /* pass to server */
/* NOT REACHED*/
return; /* ?? should never reach here */
case 'R': /* reshaped */
DO DEBUG("CMD 'R' reshape chan %c\n", buff[1]);
if (size != 2 + ATTRSIZE) /* verify size */
break; /* break if bad */
if (chan == 0) /* verify channel */
break; /* break if bad */
/* build shape structure */
if (parseshape(&shape, &buff[2]) == -1)
break; /* if invalid data then bad packet */
ReceiveReshape(chan, &shape); /* tell server about shape */
return; /* packet processed */
case 'S': /* signal */
DO DEBUG("CMD 'S' SIGNAL chan %c sig %c\n", buff[1], buff[2]);
if (size != 3) /* verify size */
break; /* break if bad */
if (chan == 0)
break; /* break if bad */
if (buff[2] == '0') /* if SIGINT */
size = SIGINT; /* yes */
else
if (buff[2] == '1') /* if SIGHUP */
size = SIGHUP; /* yes */
else
break; /* invalid signal */
ReceiveSignal(chan, size); /* pass to server */
return; /* packet processed */
default:
DO DEBUG("ILLEGAL CONTROL PACKET!!!\n");
return; /* ignore bad packet */
} /* end command packet switch */
/* switch falls out if bad size or channel for given command */
DO DEBUG("Invalid size or channel!!!\n"); /* dump error */
return; /* ignore packet */
} /* Packet() */
/* GetData() - read next input from MacLayers stream */
/* The settimeout variable indicates if we return when nothing
** is read within a certain amount of seconds. The return code is:
**
** 0 - timeout occured and no data was read
**
** 1 - no timeout occured, data read
*/
static int
GetData()
{
int result; /* return from read() */
int i; /* work counter */
char *ptr; /* work pointer */
DO dumptime();
DO DEBUG("GetData()\n");
/* if buffer still has data simply return (SHOULD NOT OCCUR?) */
if (insize > 0)
{ DO DEBUG("early return insize %d\n", insize);
return ( 1 ); /* act as through data read */
}
inpos = inbuff; /* next get will start at beginning */
insize = 0; /* default insize back to zero */
/* set timeout if we are to do so */
if (settimeout)
{ DO DEBUG("alarm(%d)\n", settimeout);
(void) alarm(settimeout); /* set timeout in seconds */
}
/* do the read from stdin */
result = read(0, inbuff, IOSIZE);
/* if alarm was set cancel it now */
if (settimeout)
{ DO DEBUG("alarm(0)\n");
myalarm(0); /* cancel alarm */
}
/* check for timeout or error */
/* EWOULDBLOCK for no data avail -(but we should not see this) */
/* EINTR if signal stopped the read -(rare but could happen) */
if (result <= 0)
{ DO DEBUG(" ?? no data result %d\n", result);
return ( 0 ); /* return nothing read */
}
/* return with fresh buffer data */
insize = result;
/* if 7-bit communication channel then strip all high bits */
if (Sevenbits)
for (i=result,ptr = inbuff; i>0; --i)
*ptr++ &= 0x7f; /* strip high bit */
DO DEBUG("read %d bytes\n", insize);
return ( 1 ); /* return OK code */
} /* GetData() */
/* AwaitInput() - wait for more input from MacLayers */
static void
AwaitInput()
{
int r; /* read descriptor bits */
DO dumptime();
DO DEBUG("AwaitInput() insize %d\n", insize);
/* if buffer has data then don't wait */
if (insize > 0)
{ DO DEBUG("Return early insize %d\n", insize);
return;
}
do
{ r = 1<<0; /* wait for read from input device */
if (select(32, (fd_set *) &r, (fd_set *) NULL, (fd_set *) NULL,
(struct timeval *) NULL) == -1) /* if problem waiting ... */
{ if (errno != EINTR) /* if not simply signal taken ... */
{ /* SHOULD NOT OCCUR - shutdown layers */
DO DEBUG("AwaitInput: select error %d\n", errno);
printf("layers: AwaitInput: bad select %d\n", errno);
FQuit(); /* shutdown layers */
/* NOT REACHED */
}
}
} while ((r & 1<<0) == 0);
} /* AwaitInput() */
/* asciishape() - convert Shape structure to ASCII */
static void
asciishape(shape, loc)
struct Shape *shape; /* Shape structure for channel */
char *loc; /* location to start filling result */
{
char *origloc; /* (for debuggin) */
origloc = loc; /* remember start of string */
fill4(&loc, shape->worigh); /* origin h */
fill4(&loc, shape->worigv); /* origin v */
fill2(&loc, shape->wlines); /* lines high */
fill2(&loc, shape->wchars); /* chars wide */
fill1(&loc, shape->wfont); /* font size */
fill2(&loc, shape->wattr); /* attributes */
DO DEBUG("asciishape(): %.*s\n", ATTRSIZE, origloc);
} /* asciishape() */
/* fill4() - convert parameter to ASCII */
static void
fill4(loc, valu)
char **loc; /* pointer to fill area pointer */
unsigned valu; /* value to use */
{
fill2(loc, valu>>8); /* fill high half word */
fill2(loc, valu & 0xff); /* fill low half word */
} /* fill4() */
/* fill2() - convert parameter to ASCII */
static void
fill2(loc, valu)
char **loc; /* pointer to fill area pointer */
unsigned valu; /* value to use */
{
fill1(loc, valu>>4); /* fill high byte */
fill1(loc, valu & 0xf); /* fill low byte */
} /* fill2() */
/* fill1() - convert parameter to ASCII */
static void
fill1(loc, valu)
char **loc; /* pointer to fill area pointer */
unsigned valu; /* value to use */
{
*(*loc)++ = "0123456789ABCDEF"[valu & 0xf]; /* return hex value */
} /* fill1() */
/* parseshape() - convert ASCII image to Shape structure */
static int Badconvert; /* indicates bad conversion */
static int
parseshape(shape, loc)
struct Shape *shape; /* Shape structure for channel */
char *loc; /* location to start parsing */
{
Badconvert = 0; /* clear bad characters indicator */
shape->worigh = get4(&loc); /* origin h */
shape->worigv = get4(&loc); /* origin v */
shape->wlines = get2(&loc); /* lines high */
shape->wchars = get2(&loc); /* chars wide */
shape->wfont = get1(&loc); /* font size */
shape->wattr = get2(&loc); /* attributes */
DO DEBUG("ParseShape(): origv %d, origh %d, lines %d, chars %d\n",
shape->worigv, shape->worigh, shape->wlines, shape->wchars);
DO DEBUG(" font %d, attr 0x%x, badconv %d\n",
shape->wfont, shape->wattr, Badconvert);
return ( Badconvert ? -1 : 0 ); /* return conversion code */
} /* parseshape() */
/* get4() - convert ASCII to parameter */
static unsigned
get4(loc)
char **loc; /* pointer to fill area pointer */
{
unsigned hi; /* high portion */
unsigned low; /* low portion */
hi = get2(loc); /* get high byte */
low = get2(loc); /* get low byte */
return ( (hi<<8) + low ); /* return word value */
} /* get4() */
/* get2() - convert ASCII to parameter */
static unsigned
get2(loc)
char **loc; /* pointer to fill area pointer */
{
unsigned hi; /* high portion */
unsigned low; /* low portion */
hi = get1(loc); /* get high half */
low = get1(loc); /* get low half */
return ( (hi<<4) + low ); /* return byte value */
} /* get2() */
/* get1() - convert ASCII to parameter */
/* This function sets 'Badconvert' if an invalid character is detected */
static unsigned
get1(loc)
char **loc; /* pointer to fill area pointer */
{
int c; /* character to convert */
c = *(*loc)++; /* fetch character */
if (c >= '0' && c <= '9')
/* zero through nine */
return ( c - '0' ); /* return it's binary value */
if (c >= 'a' && c <= 'f')
/* lower case hex */
return ( c - 'a' + 10); /* return it's binary value */
if (c >= 'A' && c <= 'F')
/* upper case hex */
return ( c - 'A' + 10); /* return it's binary value */
/* invalid digit! */
Badconvert++; /* set bad character flag */
return ( 0 ); /* return a zero */
} /* get1() */
/* myscanf() - RAW mode scanf routine */
/** This routine is required because once our terminal is set into RAW mode
*** the standard scanf routine fails on 7-bit lines whenever a high bit
*** occurs in an input character. Only the %d, %c and exact input character
*** images are supported in the input format string. All value parameters
*** must be integer data type for both %d and %c.
*/
static int
myscanf(str, arg1, arg2, arg3)
unsigned char *str; /* scanf input string */
int *arg1,*arg2,*arg3; /* integer input pointer arguments */
{
int numscan = 0; /* items filled in */
int build; /* %d build integer value */
int c; /* integer input character */
DO dumptime();
DO DEBUG("myscanf(%s)\n", str);
/* scan string processing formats */
while (*str)
switch (*str)
{ case EOF:
/* Error: probably our alarm timed out */
return ( numscan );
/* NOT REACHED */
case '%':
/* format specifier */
switch (*++str)
{ case 'c':
/* return next character as is */
if ((build=mygetchar()) == -1)
return ( numscan ); /* no input, return count */
break;
case 'd':
/* build input decimal value */
build = 0;
while ((c=mygetchar()) >= '0' && c <= '9')
{ build = build * 10; /* next base ten digit */
build += c - '0'; /* add this digit */
}
myungetc(c); /* return character ending number */
break;
default:
return ( numscan ); /* return if error */
/* NOT REACHED */
}
/* return value to correct input parameter */
switch (numscan)
{ case 0:
*arg1 = build;
break;
case 1:
*arg2 = build;
break;
case 2:
*arg3 = build;
break;
default:
/* SHOULD NOT OCCUR */
return ( numscan );
/* NOT REACHED */
}
numscan++; /* count items scanned */
str++; /* bump scan string past 'd' */
break; /* continue scan */
default:
/* input character must match exactly */
c = mygetchar();
if (c != *str)
return ( numscan ); /* return - we don't match string */
str++; /* to next character */
} /* end scan string char switch */
/* return number of items scanned */
return ( numscan );
} /* myscanf() */
/* mygetchar() - get character stripped to 7 bits */
/* Return: -1 if timeout
** char stripped to 7 bits
*/
static int
mygetchar()
{
int c; /* next input character */
int result; /* read return value */
DO dumptime();
/* if character still in buffer return it */
if (insize > 0)
{ insize--; /* count down */
c = (*inpos++) & 0x7f; /* fetch next char */
DO DEBUG(" 0x%lx '%c' ", c, c);
return ( c ); /* return 7-bit character */
}
/* attempt to read the buffer */
result = GetData(); /* no timeout (caller may have set) */
/* return -1 if timeout */
if (result == 0)
{ DO DEBUG(" mygetchar ret -1\n");
return ( -1 );
}
return ( mygetchar() ); /* return next character */
#if 0
c = getchar() & 0x7f; /* insure 7-bit only */
DO DEBUG(" 0x%lx '%c' ", c, c);
return ( c );
#endif
} /* mygetchar() */
/* myungetc() - unget a character */
/* Must only be called to return when a character was previously fetched */
static void
myungetc(c)
int c; /* character to unget */
{
DO dumptime();
DO DEBUG("myungetc(x%lx/%c)\n", c, c);
insize++; /* count back up by one */
*--inpos = c; /* restore previous character */
} /* myungetc() */
/* myalarm() - setup alarm timeout for next read */
static void
myalarm(time)
int time; /* time in seconds (or zero) */
{
DO dumptime();
DO DEBUG("myalarm(%d)\n", time);
settimeout = time; /* set for next read */
} /* myalarm() */
/* dumptime() - print out time in seconds */
/* THIS MAY BE SYSTEM DEPENDENT SO IS BASED UPON DEBUG IFDEF */
#ifdef DUMPALL
#include <sys/types.h>
#include <sys/time.h>
#endif
static void
dumptime()
{
#ifdef DUMPALL
time_t seconds;
static time_t base;
if (base == 0)
{ seconds = 0;
base = time(NULL);
}
else
seconds = time(NULL) - base;
DO DEBUG("[%3d] ", seconds);
#endif
} /* dumptime() */